#!/usr/bin/python


import os
import pickle
from constants import *
from my_exceptions import *
import logging


logger = logging.getLogger("OntologyManager")



class OntologyManager(object):
	
	def __init__(self, interface, ontologies_storage_file, priority_system=DEFAULT_PRIORITY):
		"""
			:Parameters:
				`interface` : Interface
					The Interface used to communicate with the database, mainly to retrieve the ontologies.
				`ontologies_storage_file` : str
					The path to the file storing the ontologies the selected by the users. Used (at least) to retrieve them in the getSelectedOntologies() method. May be set to None if you are NEVER going to use method that need access to that file (currently getSelectedOntologies()).
				`priority_system` : Priority
					The priority system that is used to determine which method to call at which priority level.
		"""
		
		logger.debug("__init__(%s, %s, %s)" % (interface, ontologies_storage_file, priority_system))
		
		self.i = interface
		self.file = ontologies_storage_file
		self.priority_system = priority_system
		
		# tries to get the soprano ontology loader.
		import dbus
		try:
			self.loader = dbus.SessionBus().get_object("org.kde.nepomuk.services.nepomukontologyloader", "/nepomukontologyloader")
		except Exception, e:
			logger.debug("Impossible to get the ontology loader: %s" % e)
			self.loader = None

############################################################

	def getOwnOntologies(self):
		""" Returns the ontologies defined as "own" ones, meaning owned by the user.
			:Returns: The wanted ontologies - set(str).
		"""
		
		query = "SELECT ?onto WHERE { ?onto <" + RDF_TYPE + "> <" + NRL_ONTOLOGY + "> FILTER regex(str(?onto), \"resources/ontologies/own\") }"
		ontologies = self.i.executeQuery(query)
		
		#logger.debug("query = %s", query)
		
		ontologies_res = set()
		while ontologies.next():
			ontology = ontologies.current()[0]["onto"][1]
			ontologies_res.add(ontology)
		
		ontologies.close()
		return ontologies_res

############################################################

	def getSelectedOntologies(self):
		""" Returns the ontologies stored in the self.file. These are the ontologies selected by the user through the ontologies.xul panel.
			:Returns: The wanted ontologies - set(str).
		"""
		
		if self.file == None:
			raise CanNotException("Can not get the selected ontologies as no storage file is defined.")
		
		ontologies = set()
		if os.access(self.file, os.F_OK):
			f = file(self.file, "r")
			ontologies = pickle.load(f)
			f.close()
		else:
			raise CanNotException("File %s is not accessible." % self.file)
		
		logger.debug("\tOntologies: %s" % ontologies)
		return ontologies

############################################################

	def getNonTechnicalOntologies(self):
		""" Returns the ontologies that are non-technical, meaning the common ontologies in which some properties of interest for the user are stored.
			:Returns: The wanted ontologies - set(str).
		"""
		
		return set([ONTO_PIMO, ONTO_NAO, ONTO_NIE, ONTO_NFO, ONTO_NMO, ONTO_NCO])

############################################################

	# possible status values are "Unstable", "Stable" and "Testing"
	def getAllOntologies(self, status="any"):
		""" Returns all NRL_ONTOLOGYs stored as such in the database.
			:Parameters:
				`status` : str
					Restrict the retrieved ontologies by their status. If status is omitted or set to "any", there will not be any restriction. (This parameter is not used at this time.)
			:Returns: The wanted ontologies - set(str).
		"""
		
		logger.debug("getAllOntologies")
		
		if status == "any":
			query = "SELECT ?onto WHERE { ?onto <" + RDF_TYPE + "> <" + NRL_ONTOLOGY + "> }"
		else:
			query = "SELECT ?onto WHERE { ?onto <" + RDF_TYPE + "> <" + NRL_ONTOLOGY + "> ?onto <" + NAO_STATUS + "> \"" + status + "\"^^<" + XMLSCHEMA_STRING + "> }"
		
		ontologies = self.i.executeQuery(query)
		
		ontologies_res = set()
		while ontologies.next():
			ontology = ontologies.current()[0]["onto"][1]
			ontologies_res.add(ontology)
		
		ontologies.close()
		
		logger.debug("\tOntologies: %s" % ontologies_res)
		return ontologies_res

############################################################

	def getAllContexts(self):
		""" Gets all the contexts (= graphs = 4th node in a statement) stored in database (less specific than only ontologies).
			:Returns: The wanted ontologies - set(str).
		"""
		
		query = "SELECT DISTINCT ?onto WHERE { GRAPH ?onto { ?res ?rel ?obj } }"
		ontologies = self.i.executeQuery(query)
		
		ontologies_res = set()
		while ontologies.next():
			ontology = ontologies.current()[0]["onto"][1]
			ontologies_res.add(ontology)
		
		ontologies.close()
		
		#logger.debug("\tOntologies: %s" % ontologies_res)
		return ontologies_res

############################################################

	def getOntologiesAtLevel(self, priority_level):
		""" Gets the set of ontologies corresponding to the given priority_level.
			:Parameters:
				`priority_level` : int
					The considered priority_level.
			:Returns: The wanted ontologies - set(str). A void set if the method corresponding to the given priority_level can not be called. None if the given priority_level does not exist.
		"""
		
		# get the ontologies corresponding to the given priority_level
		getOntologies = None
		ontologies = None
		try:
			getOntologies = self.__getattribute__(self.priority_system.priority_levels[priority_level].ontologies)
			logger.debug("getOntologiesAtLevel calls %s" % getOntologies)
			ontologies = getOntologies()
			return ontologies
		except CanNotException, e:
			# e.g. "Can not get the selected ontologies as no storage file is defined."
			logger.debug("CanNotException: \"%s\"." % e)
			return set()
		except AttributeError, e:
			logger.debug("Function at this level is not defined for this OntologyManager, acting like this function had returned a void set (%s)." % e)
			return set()
		except IndexError, e:
			logger.debug("There is not such a priority_level (priority_level = %s, error is \"%s\")." % (priority_level, e))
			return None

############################################################

	def getPriorityLevelDescription(self, priority_level):
		""" Gets the user-readable description of the given priority_level. Used for graphical display.
			:Parameters:
				`priority_level` : int
					The considered priority_level.
			:Returns: The description for that priority_level.
		"""
		
		try:
			priority_level_description = self.priority_system.priority_levels[priority_level].description
			return priority_level_description
		except:
			return None

############################################################

	def importOntology(self, ontology_uri):
		""" Imports the given ontology_uri. No information is treated, at this time, so that the user does not know whether the ontology has successfully loaded. The corresponding interface currently provides a "refresh ontologies" button so that the user can "check it him/herself". Will probably be better with an event watcher to catch "successfully loaded" or "not loaded" events.
			:Parameters:
				`ontology_uri` : str
					The URI of the ontology we want to load.
			:Returns: False if the loader is not accessible (via dbus), True if it is.
		"""
		
		logger.debug("importOntology(%s)" % ontology_uri)
		
		if self.loader == None:
			return False
		
		self.loader.importOntology(ontology_uri)
		return True

############################################################







